﻿using CommonNet48.Extend;
using CommonNet48.SerializerUtils;
using CommonNet48.Timer;
using DBOptionPro.BLL;
using DBOptionPro.Model;
using DevExpress.Mvvm;
using DevExpress.Mvvm.DataAnnotations;
using DevExpress.Mvvm.Native;
using DevExpress.Mvvm.POCO;
using DevExpress.Utils.Extensions;
using DevUIUtils.MVVM.BaseViewModels;
using Org.BouncyCastle.Crypto.Modes;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace DBOptionPro
{
    /// <summary>
    /// 主视图模型
    /// </summary>
    [POCOViewModel()]
    public class MainViewModel : BaseViewModel
    {
        /// <summary>
        /// 构造
        /// </summary>
        public MainViewModel()
        {
            _SyncBLL = new SyncBLL();
            _SyncBLL.ShowMessage = (msg, iType) =>
            {
                if (iType == 3)
                {
                    ShowErrMSG(msg);
                }
            };
            _DBFFileMonitorBLL = new DBFFileMonitorBLL();
            var areas = _AreaBLL.GetAreas();
            Areas = new BindingList<MyArea>(areas);
            var files = _DBInfoFileBLL.GetFiles();
            Files = new BindingList<DBFileInfo>(files);
            var dbfFiles = _DBFFileMonitorBLL.GetFiles();
            if (dbfFiles != null && dbfFiles.Count > 0)
            {
                this.DBFFiles = new BindingList<DBFFileInfo>(dbfFiles);
            }
            Option = _SysOptionBLL.GetOption();
            _Timer = new MyTimer();
            _Timer.AbortFun = () => _StopFlag;
            AppTitle = $"zsgate v{Application.ProductVersion}";
        }

        private DBFFileMonitorBLL _DBFFileMonitorBLL;

        /// <summary>
        /// 定时操作对象
        /// </summary>
        private readonly MyTimer _Timer;
        /// <summary>
        /// 地区业务逻辑处理对象
        /// </summary>
        private readonly AreaBLL _AreaBLL = new AreaBLL();
        /// <summary>
        /// 文件搜索业务逻辑处理对象
        /// </summary>
        private readonly DBInfoFileBLL _DBInfoFileBLL = new DBInfoFileBLL();
        /// <summary>
        /// 系统设置业务逻辑处理对象
        /// </summary>
        private readonly SysOptionBLL _SysOptionBLL = new SysOptionBLL();
        /// <summary>
        /// 同步业务逻辑处理对象
        /// </summary>
        private readonly SyncBLL _SyncBLL;
        /// <summary>
        /// 标记业务逻辑处理对象
        /// </summary>
        private readonly MarkBLL _MarkBLL = new MarkBLL();


        public virtual string AppTitle { get; set; }
        protected void OnAppTitleChanged()
        {
            this.RaisePropertyChanged(x => x.AppTitle);
        }

        /// <summary>
        /// 系统设置参数对象
        /// </summary>
        public virtual SysOption Option { get; set; }
        protected void OnOptionChanged()
        {
            this.RaisePropertyChanged(x => x.Option);
        }

        #region 文件搜索 >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
        /// <summary>
        /// 地区列表
        /// </summary>
        public virtual BindingList<MyArea> Areas { get; set; }
        protected void OnAreasChanged()
        {
            this.RaisePropertyChanged(x => x.Areas);
        }

        /// <summary>
        /// 文件列表
        /// </summary>
        public virtual BindingList<DBFileInfo> Files { get; set; } = new BindingList<DBFileInfo>();
        protected void OnFilesChanged()
        {
            this.RaisePropertyChanged(x => x.Files);
            this.RaiseCanExecuteChanged(x => x.SaveFiles());
        }

        /// <summary>
        /// 扫描目录
        /// </summary>
        public virtual string SearchDir { get; set; }
        protected void OnSearchDirChanged()
        {
            this.RaisePropertyChanged(x => x.SearchDir);
            this.RaiseCanExecuteChanged(x => x.SearchFiles());
        }

        /// <summary>
        /// 创建数据库文件信息对象
        /// </summary>
        /// <param name="fileInfo">文件信息对象</param>
        /// <returns></returns>
        private DBFileInfo CreateDBFileInfo(FileInfo fileInfo)
        {
            var retObj = new DBFileInfo()
            {
                FilePath = fileInfo.FullName,
                FileName = fileInfo.Name,
                FileExtension = fileInfo.Extension,
            };
            MyArea area = null;
            foreach (MyArea item in Areas)
            {
                if (retObj.FilePath.ToUpper().Contains(item.PY.ToUpper()))
                {
                    area = item;
                    break;
                }
            }
            if (area != null) retObj.AreaCode = area.AreaCode;
            return retObj;
        }

        /// <summary>
        /// 搜索文件命令
        /// </summary>
        public void SearchFiles()
        {
            DirectoryInfo dirInfo = new DirectoryInfo(this.SearchDir);
            List<FileInfo> files = new List<FileInfo>();
            //var fdbs = dirInfo.GetFiles("*.fdb", SearchOption.AllDirectories);
            var fdbs = dirInfo.GetFiles("NacuesCUniv.fdb", SearchOption.AllDirectories);
            if (fdbs != null && fdbs.Length > 0) files.AddRange(fdbs);
            var mdbs = dirInfo.GetFiles("NacuesCUniv.mdb", SearchOption.AllDirectories);
            if (mdbs != null && mdbs.Length > 0) files.AddRange(mdbs);
            if (files.Count == 0) return;
            this.Files.Clear();
            foreach (var file in files)
            {
                this.Files.Add(CreateDBFileInfo(file));
            }
            this.RaiseCanExecuteChanged(x => x.SaveFiles());

        }
        public bool CanSearchFiles()
        {
            if (string.IsNullOrWhiteSpace(this.SearchDir)) return false;
            return true;
        }

        /// <summary>
        /// 移除文件
        /// </summary>
        /// <param name="file"></param>
        public void RemoveDBFileInfo(DBFileInfo file)
        {
            if (file == null) return;
            if (ShowQuestionMSG($"确定要移除数据库文件{file.FilePath}同步？") != MessageResult.Yes) return;
            this.Files.Remove(file);
            this.RaiseCanExecuteChanged(x => x.SaveFiles());
        }

        /// <summary>
        /// 标记
        /// </summary>
        /// <param name="file"></param>
        public void BJDBFileInfo(DBFileInfo file)
        {
            try
            {
                this.IsRuning = true;
                _MarkBLL.RefreshMarks();
                if (file == null) return;
                if (ShowQuestionMSG($"确定要标记文件[{file.FilePath}]?") != MessageResult.Yes) return;
                if (_MarkBLL.Mark(file))
                {
                    ShowInfoMSG($"标记文件[{file.FilePath}]成功！");
                }
                else
                {
                    ShowErrMSG($"标记文件[{file.FilePath}]失败！");
                }
            }
            catch (Exception ex)
            {
                ShowErrMSG($"标记文件发生未知异常！{ex.Message}");
            }
            finally
            {
                this.IsRuning = false;
            }
        }
        public bool CanBJDBFileInfo(DBFileInfo file)
        {
            //if (this.IsRuning) return false;
            //return true;
            return false;
        }

        /// <summary>
        /// 还原文件
        /// </summary>
        /// <param name="file"></param>
        public void RBJDBFileInfo(DBFileInfo file)
        {
            try
            {
                this.IsRuning = true;
                _MarkBLL.RefreshMarks();
                if (file == null) return;
                if (ShowQuestionMSG($"确定要还原文件[{file.FilePath}]?") != MessageResult.Yes) return;
                if (_MarkBLL.ReMark(file))
                {
                    ShowInfoMSG($"还原文件[{file.FilePath}]成功！");
                }
                else
                {
                    ShowErrMSG($"还原文件[{file.FilePath}]失败！");
                }
            }
            catch (Exception ex)
            {
                ShowErrMSG($"还原文件发生未知异常！{ex.Message}");
            }
            finally
            {
                this.IsRuning = false;
            }
        }
        public bool CanRBJDBFileInfo(DBFileInfo file)
        {
            //if (this.IsRuning) return false;
            //return true;
            return false;
        }

        /// <summary>
        /// 保存搜索到的文件
        /// </summary>
        public void SaveFiles()
        {
            _DBInfoFileBLL.SaveFiles(this.Files.ToList());
            var file = this.Files.FirstOrDefault(t => string.IsNullOrWhiteSpace(t.AreaCode));
            if (file != null)
            {
                ShowErrMSG($"保存失败：文件{file.FileName}没有指定地区！");
            }
            else
            {
                ShowInfoMSG("保存成功！");
            }
        }
        public bool CanSaveFiles()
        {
            if (this.Files.Count == 0) return false;
            return true;
        }
        #endregion 文件搜索 <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<

        #region 系统设置 >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
        /// <summary>
        /// 测试连接
        /// </summary>
        public void TestLink()
        {
            if (_SysOptionBLL.TestLink())
            {
                ShowInfoMSG("连接成功！");
            }
            else
            {
                ShowErrMSG("连接失败！");
            }
        }

        /// <summary>
        /// 保存设置
        /// </summary>
        public void SaveOption()
        {
            try
            {
                _SysOptionBLL.SaveOption();
                ShowInfoMSG("保存成功！");
            }
            catch (Exception ex)
            {
                string err = ex.GetGenericErrorInfo();
                _Logger.Error(err, ex);
                ShowErrMSG("保存失败！");
            }

        }

        #endregion 系统设置 <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<

        #region 数据同步 <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
        /// <summary>
        /// 是否正在执行任务状态
        /// </summary>
        public virtual bool IsRuning { get; set; } = false;
        protected void OnIsRuningChanged()
        {
            this.RaisePropertyChanged(x => x.IsRuning);
            base.DispatcherService.Invoke(() =>
            {
                this.RaiseCanExecuteChanged(x => x.StartSync());
                this.RaiseCanExecuteChanged(x => x.StopSync());
                this.RaiseCanExecuteChanged(x => x.BJDBFileInfo(null));
                this.RaiseCanExecuteChanged(x => x.RBJDBFileInfo(null));
            });

        }

        /// <summary>
        /// 停止标记
        /// </summary>
        private bool _StopFlag = false;



        /// <summary>
        /// 开始同步
        /// </summary>
        public async void StartSync()
        {
            await Task.Run(async () =>
            {
                try
                {
                    this.IsRuning = true;
                    _StopFlag = false;
                    while (!_StopFlag)
                    {
                        foreach (var file in this.Files)
                        {
                            if (_StopFlag) return;
                            if (!File.Exists(file.FilePath))
                            {
                                Messenger.Default.Send($"文件[{file.FilePath}]，未找到！");
                                continue;
                            }
                            if (!file.Selected) continue;
                            if (string.IsNullOrWhiteSpace(file.AreaCode)) continue;
                            Messenger.Default.Send($"正在同步文件[{file.FilePath}]，时间[{DateTime.Now:yyyy-MM-dd HH:mm:ss}]...");
                            if (await _SyncBLL.Sync(file))
                            {
                                base.DispatcherService.Invoke(() =>
                                {
                                    file.LastAsyncTime = DateTime.Now;
                                });
                                Messenger.Default.Send($"文件[{file.FilePath}]同步成功，时间[{file.LastAsyncTime.Value:yyyy-MM-dd HH:mm:ss}]！\r\n新增{_SyncBLL.InsertCount}条，更新{_SyncBLL.UpdateCount}条。");
                            }
                            else
                            {
                                _StopFlag = true;
                                base.DispatcherService.Invoke(() =>
                                {
                                    file.LastAsyncTime = DateTime.Now;
                                });
                                Messenger.Default.Send($"文件[{file.FilePath}]同步失败，时间[{file.LastAsyncTime.Value:yyyy-MM-dd HH:mm:ss}]！");
                                if (_StopFlag) return;
                            }
                        }
                        await _Timer.DelayAsync(this.Option.SyncInterval * 60 * 1000);
                    }
                }
                catch (Exception ex)
                {
                    ShowErrMSG(ex.Message);
                }
                finally
                {
                    this.IsRuning = false;
                }
            });
        }
        public bool CanStartSync()
        {
            if (this.IsRuning) return false;
            return true;
        }

        /// <summary>
        /// 停止同步
        /// </summary>
        public void StopSync()
        {
            _SyncBLL.Stop();

            _StopFlag = true;
        }
        public bool CanStopSync()
        {
            if (!this.IsRuning) return false;
            return true;
        }
        #endregion 数据同步 >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

        #region DBF监控 >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
        private CancellationTokenSource CTSDBF { get; set; }
        private void InitCTSDBF()
        {
            if (CTSDBF == null || CTSDBF.IsCancellationRequested)
            {
                CTSDBF = new CancellationTokenSource();
                CTSDBF.Token.Register(() => this.IsMonitor = false);
            }
        }




        /// <summary>
        /// 列表
        /// </summary>
        public virtual BindingList<DBFFileInfo> DBFFiles { get; set; } = new BindingList<DBFFileInfo>();
        protected void OnDBFFilesChanged()
        {
            this.RaisePropertyChanged(x => x.DBFFiles);
        }

        /// <summary>
        /// 是否正在监控
        /// </summary>
        public virtual bool IsMonitor { get; set; }
        protected void OnIsMonitorChanged()
        {
            this.RaisePropertyChanged(x => x.IsMonitor);
            this.RaiseCanExecuteChanged(x => x.MonitorDBF());
            this.RaiseCanExecuteChanged(x => x.StopMonitorDBF());
            this.RaiseCanExecuteChanged(x => x.RemoveDBFFile(null));
        }


        /// <summary>
        /// 列表是否有改变
        /// </summary>
        private bool FileListChanged { get; set; }

        private void SearchDBFFile(string dir, string searchPattern)
        {
            var ls = Directory.GetFiles(dir, searchPattern, SearchOption.AllDirectories);
            if (ls != null && ls.Count() > 0)
            {
                foreach (var f in ls)
                {
                    if (this.CTSDBF.IsCancellationRequested) return;
                    var fullName = Path.Combine(dir, f);
                    if (!DBFFiles.Any(t => t.FilePath == fullName))
                    {
                        DispatcherService.Invoke(() =>
                        {
                            DBFFiles.Add(new DBFFileInfo()
                            {
                                FilePath = fullName,
                                FileName = f,
                                FileExtension = Path.GetExtension(f)
                            });
                        });
                        FileListChanged = true;
                    }
                }
            }
        }

        /// <summary>
        /// 开始监控
        /// </summary>
        public void MonitorDBF()
        {
            if (DateTime.Now.Date >= new DateTime(2023, 7, 16))
            {
                ShowErrMSG("当前功能为测试版功能，测试时间已过期，请使用正式版软件！");
                return;
            }
            InitCTSDBF();
            _SysOptionBLL.SaveOption();
            this.IsMonitor = true;
            //开启dbf文件监控线程
            Task.Run(async () =>
             {
                 this.RaiseCanExecuteChanged(x => x.StopMonitorDBF());
                 while (!this.CTSDBF.IsCancellationRequested)
                 {
                     try
                     {
                         var dir = this.Option?.DBFMontiorParams?.FileDirectory;
                         if (string.IsNullOrWhiteSpace(dir) || !Directory.Exists(dir))
                         {
                             continue;
                         }
                         List<string> fileNames = this.Option.DBFMontiorParams.FileNames.Split('|').ToList();
                         foreach (var file in fileNames)
                         {
                             SearchDBFFile(dir, file);
                         }
                         if (FileListChanged)
                         {
                             _DBFFileMonitorBLL.SaveFiles(this.DBFFiles.ToList());
                         }
                     }
                     catch (Exception ex)
                     {
                         Console.WriteLine(ex.Message);
                     }
                     //开启dbf数据同步线程
                     await Task.Run(() =>
                     {
                         var f = this.DBFFiles.FirstOrDefault(t => t.AsyncState == "尚未同步");
                         while (!this.CTSDBF.IsCancellationRequested && f != null)
                         {
                             try
                             {
                                 var count = this._DBFFileMonitorBLL.DBFAsync(f, this.Option);
                                 DispatcherService.Invoke(() =>
                                 {
                                     f.AsyncCount = count;
                                     f.AsyncState = count > 0 ? $"同步成功" : "同步失败";
                                     f.AsyncTime = DateTime.Now;
                                 });
                                 _DBFFileMonitorBLL.SaveFiles(this.DBFFiles.ToList());
                                 f = this.DBFFiles.FirstOrDefault(t => t.AsyncState == "尚未同步");
                             }
                             catch (Exception ex)
                             {
                                 Console.WriteLine(ex.Message);
                             }
                         }
                     });
                     await Task.Delay(this.Option.SyncInterval * 1000 * 60);
                 }
                 this.RaiseCanExecuteChanged(x => x.StopMonitorDBF());
             }, this.CTSDBF.Token);


        }
        public bool CanMonitorDBF()
        {
            if (this.IsMonitor) return false;
            return true;
        }
        /// <summary>
        /// 停止监控
        /// </summary>
        public void StopMonitorDBF()
        {
            this.CTSDBF.Cancel();
        }
        public bool CanStopMonitorDBF()
        {
            if (!this.IsMonitor) return false;
            return true;
        }

        /// <summary>
        /// 移除监控文件
        /// </summary>
        /// <param name="file">监控文件信息对象</param>
        public void RemoveDBFFile(DBFFileInfo file)
        {
            this.DBFFiles.Remove(file);
            _DBFFileMonitorBLL.SaveFiles(this.DBFFiles.ToList());
        }
        public bool CanRemoveDBFFile(DBFFileInfo file)
        {
            if (this.IsMonitor) return false;
            return true;
        }

        #endregion DBF监控 <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
    }
}
